#include "../includes/functions.h"

void ParseQueueFile(char *str, int *id, char *mess){
    int i = 0;
    for (i = 0; i < strlen(str); ++i){
        if (str[i] == ':')
            break;
    }

    str[i] = '\0';
    *id = atoi(str);
    strcpy(mess, str+i+1);
}

int Socket(struct addrinfo *ai, int (*func) (int, const struct sockaddr*, socklen_t)){
    struct addrinfo *p = ai;
    int fd;
    int yes = 1;

    for (;p != NULL; p = p->ai_next){
        fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
        if (fd < 0)
            continue;

        Setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

        if (func(fd, p->ai_addr, p->ai_addrlen) == -1){
            perror("SOCKET FAILED");
            Close(fd);
            fd = -1;
            continue;
        }
        else
            return fd;
    }

    if (fd == -1){
        fprintf(stderr, "SELECTSERVER: SOCKET FAILED\n");
        exit(EXIT_FAILURE);
    }
}


void PrintQueue(int fd){
    char buf[MAX_SIZE];
    
    Recv(fd, buf, MAX_SIZE);
    
    if (Strcmp(buf, FAILED))
        printf("QUEUE IS EMPTY\n");
    else{
        while (!Strcmp(buf, OK)){
            printf("%s", buf);
            memset(buf, 0, sizeof(buf));
            Recv(fd, buf, MAX_SIZE);
        }
    }
}


int Fgets(char *restrict buf, int size, FILE * __restrict__ stream){
    int flag = 1;
    char tmp[MAX_SIZE];
    memset(buf, 0, MAX_SIZE);

    while (flag){
        if (fgets(tmp, size, stream) == NULL)
            return 0;

        if (tmp[strlen(tmp) - 1] == '\n')
            snprintf(buf, strlen(tmp), "%s", tmp);

        if (!Strcmp(buf, "\0")){
            flag = 0;
            return 1;
        }
    }
    return 1;
}


void SendQueue(const queue_t *q, int fd){
    char buf[MAX_SIZE];

    if (q->len == 0)
        Send(fd, FAILED, MAX_SIZE);
    else{
        for (int i = 0; i < q->len; ++i){

            snprintf(buf, MAX_SIZE, "%d. %s: %s\n", i+1, q->queue[i].name, q->queue[i].mess);
            Send(fd, buf, MAX_SIZE);
        }
        Send(fd, OK, MAX_SIZE);
    }
}


void CheckPassword(int fd){
    char buf[MAX_SIZE];

    printf("ENTER A PSSWORD:");

    scanf("%s", buf);

    Send(fd, buf, MAX_SIZE);

    Recv(fd, buf, MAX_SIZE);
    if (Strcmp(buf, FAILED)){
        printf("PASSWORD IS INCORRECT\n");
        exit(EXIT_FAILURE);
    }
    else if (Strcmp(buf, ADMIN_CON)){
        printf("ADMIN IS ALREADY CONNECTED\n");
        exit(EXIT_FAILURE);
    }
    else
        printf("OH YEEAAAAH...\n");
}


/* int CheckArgc(int argc, const char *argv, ...){ */
/*     va_list var_lst; */
/*     va_start(var_lst, argv); */

/*     for (int i = 1; i < argc; ++i){ */
/*         if (Strcmp( */
/*     } */
/* } */

int Strcmp(const char *str1, const char *str2){
    if (strcmp(str1, str2) == 0)
        return 1;

    return 0;
}


void PrintHelp(const char *port){
    if (Strcmp(port, PORT)){
        printf("===============================================================\n"
                "List of commands:\n"
                "1. list - displays the queue on the screen\n"
                "2. help - commands' description\n"
                "3. exit - exit the programm\n"
                "4. mess [MESSAGE] - the message will be added to the queue\n"
                "==============================================================\n");
    }
    else{
        printf("=================================================\n"
                "List of commands:\n"
                "1. list - displays the queue on the screen\n"
                "2. del - delete the first user in the queue\n"
                "3. del all - clear the entire queue\n"
                "4. help - commands' description\n"
                "5. exit - exit the programm\n"
                "================================================\n");
    }
}


char *GetCurrentTime(){
    const time_t timer = time(NULL);
    struct tm *u = localtime(&timer);
    char *s = (char*)malloc(40);

    for (int i = 0; i < 40; ++i) s[i] = 0;
    int length = strftime(s, 40, "%d.%m %H:%M:%S", u);

    return s;
}


void PrintLog(FILE *file, const char *format, va_list vars){
    if (fprintf(file, "[%s] ", GetCurrentTime()) < 0){
        fprintf(stderr, "FAILED: error reading the log file");
        exit(EXIT_FAILURE);
    }
    va_list vars_;
    va_copy(vars_, vars);

    vfprintf(file, format, vars_);

    fflush(file);
    va_end(vars_);
}


void ServerPrint(int is_log, FILE *file, const char *format, ...){
    va_list vars;
    va_start(vars, format);

    if (is_log)
        PrintLog(file, format, vars);
    
    vprintf(format, vars);
}


void MakeSqlRequire(int num, char *SQL, ...){
    char s[MAX_SIZE];
    char tmp_buf[MAX_SIZE];
    va_list vars;

    va_start(vars, SQL);
    
    for (int i = 0; i < num; ++i){
        strcpy(s, va_arg(vars, char*));
        int x = strlen(SQL) - strlen(strstr(SQL, "%s"));
        strncpy(tmp_buf, SQL, strlen(SQL) - strlen(strstr(SQL, "%s")) );
        strcat(tmp_buf, s);  
        strcat(tmp_buf, strstr(SQL, "%s") + strlen("%s"));
        strcpy(SQL, tmp_buf);
        memset(tmp_buf, 0, MAX_SIZE);
    }

    va_end(vars);
}


void SendAuthRequire(int fd, int reg, char *user_name){
    char full_name[MAX_SIZE];
    char tmp_buf[10];
    char user_pass[USER_SIZE];
    char hash_pass[65];

    printf("ENTER YOUR NAME: ");
    scanf("%s\0", user_name);
    printf("ENTER YOUR PASSWORD: ");
    scanf("%s\0", user_pass);

    if (reg)
        strcpy(tmp_buf, "RR");
        //SHA-512 for pass
    else
        strcpy(tmp_buf, "ER");

    strcpy(hash_pass, SHA256(user_pass));

    Send(fd, tmp_buf, MAX_SIZE);
    strcpy(full_name, user_name);
    strcat(full_name, "\n");
    strcat(full_name, hash_pass);

    Send(fd, full_name, MAX_SIZE);
    Recv(fd, tmp_buf, MAX_SIZE);
    if (Strcmp(tmp_buf, OK) && reg)
        printf("THE USER \"%s\" HAS BEEN SUCCESSFULLY REGISTERED\n", user_name);
    else if (Strcmp(tmp_buf, OK))
        printf("THE USER \"%s\" HAS BEEN SUCCESSFULLY LOGGED IN\n", user_name);
    else if (reg){
        printf("IT IS IMPORSSIBLE TO REGISTER\n"); 
        SendAuthRequire(fd, reg, user_name);
    }
    else{
        printf("THE USER \"%s\" IS NOT REGISTERED\n", user_name);
        SendAuthRequire(fd, reg, user_name);
    }
}


void Itoa(uint32_t num, char *res){
    int i = 0;
    while (num != 0){
        res[i++] = num % 10 + '0';
        num /= 10;
    }

    int len = strlen(res);
    for (i = 0; i < len/2; ++i){
        char tmp;
        tmp = res[i];
        res[i] = res[len - i - 1];
        res[len - i - 1] = tmp;
    }
}


void ParseDataUser(int fd, char *user_name, char *user_pass){
    int k = 0;
    char user_data[MAX_SIZE];

    Recv(fd, user_data, MAX_SIZE);
    for (int i = 0; i < strlen(user_data); ++i){
        if (user_data[i] == '\n'){
            k = i;
            break;
        }
    }
    
    strncpy(user_name, user_data, k);
    strcpy(user_pass, user_data + k + 1);
}


char *SHA256(char *data){
    int slen = strlen(data);
    SHA256_CTX ctx;
    unsigned char hash[32];
    char *hashStr = malloc(65);
    strcpy(hashStr, "");

    sha256_init(&ctx);
    sha256_update(&ctx, data, slen);
    sha256_final(&ctx, hash);

    char s[3];
    for (int i = 0; i < 32; ++i){
        sprintf(s, "%02x", hash[i]);
        strcat(hashStr, s);
    }

    return hashStr;
}

